#include <myheader.h>
typedef struct conn_s{
    int net_fd;
    time_t conn_time;
}conn_t;

/*Usage:  create a chat room */
int main(int argc, char *argv[])
{
    char *ip = "192.168.112.129";
    char *port = "8080";
    //create a socket 
    int socket_fd = socket(AF_INET,SOCK_STREAM,0);
    ERROR_CHECK(socket_fd,-1,"socket");

    //reuse port
    int optval = 1;
    int ret = setsockopt(socket_fd,SOL_SOCKET,SO_REUSEPORT | SO_REUSEADDR, 
                         &optval,sizeof(optval));
    ERROR_CHECK(ret,-1,"setsockopt");

    //bind
    struct sockaddr_in sockaddr_in;
    sockaddr_in.sin_family = AF_INET;
    sockaddr_in.sin_port = htons(atoi(port));
    sockaddr_in.sin_addr.s_addr = inet_addr(ip);

    ret = bind(socket_fd,(struct sockaddr*)&sockaddr_in,
               sizeof(sockaddr_in));
    ERROR_CHECK(ret,-1,"bind");

    //listen
    ret = listen(socket_fd,10);
    ERROR_CHECK(ret,-1,"listen");

    //save the client which connect the server
    struct conn_s list[100];//max client 100
    int listsize = 0;
    memset(list,0,sizeof(list));


    //base_set, used to record all the fd
    fd_set base_set;
    FD_ZERO(&base_set);
    FD_SET(socket_fd,&base_set);

    int net_fd = 0;
    char buf[60] = {0};
    char large_buf[100] = {0};
    while(1){
        //kick off
        //listen the net_fd and socket_fd
        fd_set listen_while;

        memcpy(&listen_while,&base_set,sizeof(base_set));
        //find the max fd
        int maxfd = 0;
        for(int fd = 0; fd < FD_SETSIZE; fd++){
            if(FD_ISSET(fd,&listen_while)){
                maxfd = (fd > maxfd) ? fd : maxfd;
            }
        }


        //prevent the select block;
        struct timeval timer;
        timer.tv_sec = 1;
        select(maxfd + 1, &listen_while,NULL,NULL,&timer);

        //kick off the user, it must put here because the select is a block function
        for(int i = 0; i < listsize; i++){
            time_t time_now = time(NULL);
           // printf("time_now = %ld\n",time_now);
           // printf("client%d time = %ld\n",i,list[i].conn_time);
            if((time_now - list[i].conn_time) > 10){

            printf("kickoff\n");
                close(list[i].net_fd);
                FD_CLR(list[i].net_fd, &base_set);
                //delete the conn in list
                for(int j = i; j < listsize - 1; j++){
                    list[j] = list[j+1];
                }
                listsize --;
            } 
        }

        //go throug all the fds in the list
        for(int fd = 0; fd <= maxfd; fd ++){
            //handle the new link
            if(fd == socket_fd && FD_ISSET(fd, &listen_while)){
                //accept
                net_fd = accept(socket_fd,NULL, NULL);
                ERROR_CHECK(net_fd,-1,"accept");

                //create conn_t
                struct conn_s conn;
                conn.net_fd = net_fd;
                list[listsize].conn_time = time(NULL);

                //save the client in list
                list[listsize] = conn;
                time_t time_now;
                time(&time_now);
                list[listsize].conn_time = time_now;
                listsize ++;
                //put the net_fd in base_set
                FD_SET(net_fd,&base_set);
            }

            //handle net_fd
            if(fd != socket_fd && FD_ISSET(fd, &listen_while)){
                //client send some msg
                memset(buf,0 ,sizeof(buf));
                memset(large_buf, 0, sizeof(large_buf));
                int read_cnt = recv(fd,buf,sizeof(buf) - 1,0);
                ERROR_CHECK(read_cnt,-1,"recv");
                buf[read_cnt] = '\0';
                //add the name 
                snprintf(large_buf,sizeof(large_buf),"netfd%d: %s",fd, buf);

                if(read_cnt == 0){
                    //delete the conn in list
                    for(int i = 0; i < listsize; i++){
                        if(list[i].net_fd == fd){
                            for(int j = i; j < listsize - 1; j++){
                                list[j] = list[j+1];
                            }
                        }
                    }
                    listsize --;
                    close(fd);
                    FD_CLR(fd,&base_set);
                    continue;
                }
                //group send
                for(int i = 0; i < listsize; i++){
                    if(list[i].net_fd == fd){
                        time_t time_now;
                        time(&time_now);
                        list[i].conn_time = time_now;
                        continue;
                    }
                    int send_cnt = send(list[i].net_fd,large_buf,strlen(large_buf),0);
                    ERROR_CHECK(send_cnt,-1,"group_send");
                }
            }
        }
    }
    return 0;
}

